package com.wjs.myspring.carolspring;

import com.wjs.myspring.carolspring.Annoation.WjsAutowired;
import com.wjs.myspring.carolspring.Annoation.WjsComponent;
import com.wjs.myspring.carolspring.Annoation.WjsQualifier;
import com.wjs.myspring.carolspring.Annoation.WjsValue;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

public class MyAnnotationConfigApplicationContext {
    private Map<String,Object> ioc=new HashMap<>();
    public MyAnnotationConfigApplicationContext(String pack){
        //遍历包，找到目标类(原材料)
        Set<BeanDefinition> beanDefinitions = getBeanDefinitions(pack);
        //根据原材料创建bean
        createObject(beanDefinitions);
        //自动装载
        autowireObject(beanDefinitions);
    }
    public Object getBean(String beanName){
        return ioc.get(beanName);
    }
    private void autowireObject(Set<BeanDefinition> beanDefinitions) {
        for (BeanDefinition definition : beanDefinitions) {
            Class clazz = definition.getBeanClass();
            //拿到所有属性的集合
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                WjsAutowired autowired = field.getAnnotation(WjsAutowired.class);
                if(autowired!=null){
                    WjsQualifier qualifier = field.getAnnotation(WjsQualifier.class);
                    if(qualifier!=null){
                       //按照name进行注入
                        try {
                            //拿到注解的值
                            String value = qualifier.value();
                            //拿到注入进属性的值
                            Object bean =getBean(value);
                            //拿到属性名
                            String fieldName = field.getName();
                            //凭借对应属性set方法名
                            String methodName="set"+fieldName.substring(0,1).toUpperCase()+fieldName.substring(1);
                            //通过反射拿到方法
                            Method method = clazz.getMethod(methodName, field.getType());
                            //获取主对象
                            Object object = getBean(definition.getBeanName());
                            //调用方法
                            method.invoke(object,bean);
                        } catch (NoSuchMethodException e) {
                            e.printStackTrace();
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        } catch (InvocationTargetException e) {
                            e.printStackTrace();
                        }
                    }else {
                        //按照类型进行注入

                        //拿到属性类型名称
                        String name = field.getType().getName();
                        //拿到ioc容器里符合条件类型的key几个
                        List<String> keyList=new ArrayList<>();
                        for (String key : ioc.keySet()) {
                            String typeName = ioc.get(key).getClass().getTypeName();
                            if(name.equals(typeName)){
                                keyList.add(key);
                            }
                        }
                        if(keyList.size()==1){
                            //当找到一个时
                            try {
                                String key = keyList.get(0);
                                Object bean = getBean(key);
                                //拿到属性名
                                String fieldName = field.getName();
                                //凭借对应属性set方法名
                                String methodName="set"+fieldName.substring(0,1).toUpperCase()+fieldName.substring(1);
                                //通过反射拿到方法
                                Method method = clazz.getMethod(methodName, field.getType());
                                //获取主对象
                                Object object = getBean(definition.getBeanName());
                                //调用方法
                                method.invoke(object,bean);
                            } catch (NoSuchMethodException e) {
                                e.printStackTrace();
                            } catch (IllegalAccessException e) {
                                e.printStackTrace();
                            } catch (InvocationTargetException e) {
                                e.printStackTrace();
                            }
                        }

                    }
                }
            }
        }
    }

    private void createObject(Set<BeanDefinition> beanDefinitions) {
        for (BeanDefinition definition : beanDefinitions) {
            Class clazz = definition.getBeanClass();
            String beanName=definition.getBeanName();
            try {
                //创建的对象
                Object object = clazz.getConstructor().newInstance();
                //完成属性的赋值
                Field[] fields = clazz.getDeclaredFields();
                for (Field field : fields) {
                    WjsValue annotation = field.getAnnotation(WjsValue.class);
                    if(annotation!=null){
                        //如果属性上添加了此注解
                        String value=annotation.value();
                        String fieldName = field.getName();
                        //设置方法名
                        String methodName="set"+fieldName.substring(0,1).toUpperCase()+fieldName.substring(1);
                        Method method = clazz.getMethod(methodName, field.getType());
                        //完成数据类型转换
                        Object val=null;
                        switch (field.getType().getName()){
                            case "java.lang.Integer":
                                val = Integer.parseInt(value);
                                break;
                            case "java.lang.String":
                                val = value;
                                break;
                            case "java.lang.Float":
                                val = Float.parseFloat(value);
                                break;
                        }
                        method.invoke(object,val);
                    }
                }
                ioc.put(beanName,object);
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        }
    }

    public Set<BeanDefinition> getBeanDefinitions(String pack){
        //获取包下所有类
        Set<Class<?>> classes = MyTools.getClasses(pack);
        Set<BeanDefinition> result=new HashSet<>();
        for (Class<?> clazz : classes) {
            //遍历这些类找到添加了注解的类
            WjsComponent wjsComponent = clazz.getAnnotation(WjsComponent.class);
            if(wjsComponent!=null){
                //获取wjsComponent注解的值
                String beanName = wjsComponent.value();
                if("".equals(beanName)){
                    //没有设置beanName时,获取类名首字母小写
                    String name = clazz.getName().replaceAll(clazz.getPackage().getName() + ".", "");
                    beanName=name.substring(0,1).toLowerCase()+name.substring(1);
                }
                //3、将这些类封装成BeanDefinition，装载到集合中
                result.add(new BeanDefinition(beanName,clazz));
            }
        }
        return result;
    }
}
